package com.wzq.animal.back.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wzq.animal.back.controller.dto.UserDTO;
import com.wzq.animal.back.pojo.Apply;
import com.wzq.animal.back.pojo.Role;
import com.wzq.animal.back.pojo.User;
import com.wzq.animal.back.service.ApplyService;
import com.wzq.animal.back.service.RoleService;
import com.wzq.animal.back.service.SendMailService;
import com.wzq.animal.back.service.UserService;
import com.wzq.animal.back.service.impl.SendMailServiceImpl;
import com.wzq.animal.common.Result;
import com.wzq.animal.common.exception.GlobalException;
import com.wzq.animal.common.exception.StatusCode;
import com.wzq.animal.utils.CipherUtils;
import com.wzq.animal.utils.CodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.Cipher;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;


@RestController
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private ApplyService applyService;

    @Autowired
    private SendMailService sendMailService;

    /**
     * 获取分页数据
     *
     * @param currentPage 当前页
     * @param pageSize    每页显示条数
     * @return
     */
    @GetMapping("/getPages/{currentPage}/{pageSize}")
    public Result getPages(@PathVariable("currentPage") int currentPage,
                               @PathVariable("pageSize") int pageSize,
                               @RequestParam("usernameKeywords") String username,
                               @RequestParam("nickNameKeywords") String nickName,
                               @RequestParam("addressKeywords") String email) {
        Page<User> page = new Page<>(currentPage, pageSize);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getUsername, username)
                .like(User::getNickName, nickName)
                .like(User::getEmail, email);
        userService.page(page, queryWrapper);
        return Result.success(page);
    }

    /**
     * 新增或者修改用户信息
     *
     * @param user 用户对象
     * @return
     */
    @PostMapping("/user")
    public Result addOrUpdateUser(@RequestBody User user) {
        userService.saveOrUpdate(user);
        Integer id = user.getId();
        if(StringUtils.isNotBlank(id.toString())){
            User updatedUser = userService.getById(id);
            return Result.success(updatedUser);
        }
        return Result.success();
    }

    /**
     * 删除单个用户
     *
     * @param id
     * @return
     */
    @DeleteMapping("/user/{id}")
    public Result delUser(@PathVariable("id") int id) {
        userService.removeById(id);
        return Result.success();
    }

    /**
     * 批量删除用户
     *
     * @param ids 要删除的用户 id 集合
     * @return
     */
    @DeleteMapping("/user")
    public Result delBatch(@RequestBody List<Integer> ids) {
        userService.removeByIds(ids);
        return Result.success();
    }

    /**
     * 导出接口
     *
     * @param response
     */
    @GetMapping("/export")
    public Result exportUsers(HttpServletResponse response) throws IOException {
        //从数据库中查询所有数据
        List<User> users = userService.list();
        //通过工具类创建 writer 写入到磁盘路径
        //ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath + "/用户信息.xlsx");
        //在内存操作，写出到浏览器
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //自定义标题别名
        //writer.addHeaderAlias("id","ID");
        //writer.addHeaderAlias("username","用户名");
        //writer.addHeaderAlias("password","密码");
        //writer.addHeaderAlias("nickName","昵称");
        //writer.addHeaderAlias("age","年龄");
        //writer.addHeaderAlias("sex","性别");
        //writer.addHeaderAlias("address","地址");
        //writer.addHeaderAlias("avatar","头像地址");
        //writer.addHeaderAlias("account","余额");

        //一次性写出 users 内的对象到 excel,使用默认样式，强制输出标题
        writer.write(users, true);
        //设置浏览器的响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息表", "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);
        out.close();
        writer.close();
        return Result.success();
    }

    /**
     * 导入接口
     *
     * @param file 传入的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/import")
    public Result importUsers(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<User> users = reader.readAll(User.class);
        System.out.println(users);
        userService.saveBatch(users);
        return Result.success();
    }

    /**
     * 登录
     * @param userDTO 用户传递的 用户名 和 密码
     * @return
     */
    @PostMapping("/login")
    public Result login(@RequestBody UserDTO userDTO) {
        if (StringUtils.isBlank(userDTO.getUsername()) || StringUtils.isBlank(userDTO.getPassword())) {
            return Result.error(StatusCode.LOGIN_EMPTY.getCode(), StatusCode.LOGIN_EMPTY.getMsg());
        } else {
            userService.checkUsername(userDTO.getUsername());
            UserDTO user = userService.checkLogin(userDTO);
            return Result.success(user);
        }
    }

    /**
     * 注册
     * @param user
     * @return
     */
    @PostMapping("/register")
    public Result register(@RequestBody User user){
        Apply apply = new Apply();
        BeanUtil.copyProperties(user,apply,true);
        //修改申请表中的审核状态
        apply.setIsSuccess(1);
        applyService.updateById(apply);
        user = userService.checkRegister(user);
        //发送邮件提醒申请者
        sendMailService.sendMail(user.getUsername(),user.getEmail(), SendMailServiceImpl.contentSucceed);
        return Result.success(user);
    }

    /**
     * 获取当前用户信息
     * @param username
     * @return
     */
    @GetMapping("/getUserInfo/{username}")
    public Result getUserInfo(@PathVariable("username") String username){
        User user = userService.checkUsername(username);
        return Result.success(user);
    }

    @GetMapping("/getUserRoleName/{roleId}")
    public Result getUserRoleName(@PathVariable("roleId") Integer roleId){
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getId,roleId);
        Role role = roleService.getOne(queryWrapper);
        return Result.success(role.getComment());
    }

    /**
     * 获取验证码
     * @param response
     */
    private String code;
    @GetMapping("/getCode")
    public void getCode(HttpServletResponse response){
        String tempCode = CodeUtils.generateCode(response);
        code = tempCode;
    }

    /**
     * 检查验证码是否正确
     * @param code
     * @return
     */
    @GetMapping("/checkCode/{code}")
    public Result checkCode(@PathVariable("code") String code){
        if(this.code.equals(code)){
            return Result.success();
        }else{
            return Result.error(StatusCode.LOGIN_CODE.getCode(),StatusCode.LOGIN_CODE.getMsg());
        }
    }

    /**
     * 通过原密码重置密码
     * @param username
     * @param oldPass
     * @param newPass
     * @return
     */
    @PostMapping("/resetPassword/{username}/{oldPass}/{newPass}")
    public Result resetPassword(@PathVariable("username")String username,@PathVariable("oldPass")String oldPass,@PathVariable("newPass")String newPass){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,username);
        User one = userService.getOne(queryWrapper);
        if(!CipherUtils.encrypt(oldPass).equals(one.getPassword())){
            log.error("++++++原密码错误");
            throw new GlobalException(StatusCode.RESET_OLDPASS);
        }else{
            one.setPassword(CipherUtils.encrypt(newPass));
            userService.updateById(one);
            return Result.success();
        }
    }

    /**
     * 通过邮件获取验证码
     * @param username
     * @param email
     * @return
     */
    @GetMapping("/getEmailCode/{username}/{email}")
    public Result getEmailCode(@PathVariable("username") String username,@PathVariable("email") String email){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,username);
        User one = null;
        try {
            one = userService.getOne(queryWrapper);
        } catch (Exception e) {
            throw new GlobalException(StatusCode.LOGIN_USERNAME);
        }
        String verificationCode = String.valueOf((int)((Math.random()*9+1)*1000));
        sendMailService.sendCode(one.getUsername(),email,SendMailServiceImpl.resetPassword,verificationCode);
        return Result.success(verificationCode);
    }

    /**
     * 通过邮箱验证码修改密码
     * @param username
     * @param newPass
     * @return
     */
    @GetMapping("/resetPassByEmail/{username}/{newPass}")
    public Result resetPassByEmail(@PathVariable("username") String username,@PathVariable("newPass") String newPass){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,username);
        User one = userService.getOne(queryWrapper);
        one.setPassword(CipherUtils.encrypt(newPass));
        userService.updateById(one);
        return Result.success();
    }
}
